// -----------------------------------------------------------------------
//  <copyright file="DbContextBase.cs" company="LiuliuSoft">
//      Copyright (c) 2022-2024 DaprPlus. All rights reserved.
//  </copyright>
//  <site>https://dapr.plus</site>
//  <last-editor>郭明锋</last-editor>
//  <last-date>2024/12/24 21:28</last-date>
// -----------------------------------------------------------------------

namespace DaprPlus.EntityFrameworkCore;

/// <summary>
/// EntityFramework数据上下文基类
/// </summary>
public abstract class DbContextBase : DbContext, IDbContext
{
    private readonly DatabaseOptions? _databaseOptions;
    private readonly IServiceProvider _provider;

    /// <summary>
    /// 无参数构造函数，仅用于单元测试
    /// </summary>
    /// <param name="provider"></param>
    [Browsable(false)]
    protected DbContextBase(IServiceProvider provider)
    {
        _provider = provider;
        _databaseOptions = provider.GetService<IOptions<DatabaseOptions>>()?.Value;
        Logger = provider.GetLogger(this);
    }

    protected DbContextBase(DbContextOptions options, IServiceProvider provider)
        : base(options)
    {
        _provider = provider;
        _databaseOptions = provider.GetService<IOptions<DatabaseOptions>>()?.Value;
        Logger = provider.GetLogger(this);
    }

    protected ILogger Logger { get; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        //向上下文注册实体配置
        //modelBuilder.Entity<EventSourcedEvent>();
        var contextType = GetType();
        var registers = _provider.GetEntityRegisters();
        foreach (var register in registers)
        {
            register.RegisterTo(modelBuilder);
            Logger.LogDebug(ResEFCore.Format_Entity_RegisterToContext, register.EntityType.Name, contextType);
        }
        Logger.LogInformation(ResEFCore.Format_Entity_RegisterToContextCount, contextType, registers.Length);

        //应用批量实体配置
        var mutableEntityTypes = modelBuilder.Model.GetEntityTypes().ToList();
        var entityBatchConfigurations = _provider.GetServices<IEntityBatchConfiguration>().ToArray();
        if (entityBatchConfigurations.Length > 0)
        {
            foreach (var mutableEntityType in mutableEntityTypes)
            {
                foreach (var entityBatchConfiguration in entityBatchConfigurations)
                {
                    entityBatchConfiguration.Configure(modelBuilder, mutableEntityType);
                }
            }
        }
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.AddInterceptors(
            new BeginOrUseTransactionInterceptor(_provider),
            new DispatchDomainEventInterceptor(_provider),
            new PickupIntegrationEventInterceptor(_provider)
            );

        base.OnConfiguring(optionsBuilder);
    }

    /// <summary>
    /// 获取 动态查询数据源
    /// </summary>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <returns></returns>
    public IQueryable<TEntity> Query<TEntity>() where TEntity : class, IEntity
    {
        return Set<TEntity>().AsNoTracking();
    }

    /// <summary>
    /// 将数据上下文转换为从库查询模式
    /// </summary>
    public void ToSlave()
    {
        if (_databaseOptions == null
            || _databaseOptions.Slaves.IsNullOrEmpty()
            || Database.GetConnectionString() != _databaseOptions.ConnectionString)
        {
            return;
        }

        var selector = _provider.GetRequiredService<ISlaveDatabaseSelector>();
        var connectionString = selector.Select(_databaseOptions.Slaves).ConnectionString;
        Database.SetConnectionString(connectionString);
    }

    /// <summary>
    /// 将数据上下文转换为主库命令模式
    /// </summary>
    public void ToMaster()
    {
        if (_databaseOptions == null
            || Database.GetConnectionString() == _databaseOptions.ConnectionString)
        {
            return;
        }

        Database.SetConnectionString(_databaseOptions.ConnectionString);
    }
}
